package com.goldgov.code.template.impl;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.goldgov.code.meta.ModuleInfo;
import com.goldgov.code.meta.RelationInfo;
import com.goldgov.code.template.Group;
import com.goldgov.code.template.Layout;
import com.goldgov.code.template.point.CodePoint;
import com.goldgov.code.template.point.PointMapping;
import com.goldgov.code.template.point.impl.ImportCodePoint;
import com.goldgov.code.template.point.impl.MemberCodePoint;
import com.goldgov.code.template.point.impl.MethodAnnotationCodePoint;
import com.goldgov.code.template.point.impl.MethodBodyCodePoint;
import com.goldgov.code.utils.CodeUtils;
import com.goldgov.code.utils.PackageUtils;
import com.goldgov.code.utils.StringUtils;

public class ServiceLayout implements Layout{

	public static final String PACKAGE_NAME = "service";
	
	@Override
	public String packageName() {
		return PACKAGE_NAME;
	}

	@Override
	public String templatePath() {
		return PACKAGE_NAME;
	}

	@Override
	public Class<?>[] dependOn() {
		return new Class[] {BeanLayout.class};
	}

	@Override
	public PointMapping codePoint(String packageName,ModuleInfo moduleInfo,Group group,Map<String,Object> paramMap) {
		PointMapping pointMapping = new PointMapping();
		
		Layout[] layouts = group.getLayouts();
		
		List<CodePoint> implPoint = pointMapping.codePoint("**/*Impl.java.ftl");
		
		RelationInfo relation = moduleInfo.getRelation();
		if(relation != null) {
			ModuleInfo relationModule = relation.getRelationModule();
			
			implPoint.add(new MethodAnnotationCodePoint("ADD",Transactional.class));
			implPoint.add(new MethodAnnotationCodePoint("UPDATE",Transactional.class));
			implPoint.add(new ImportCodePoint(Transactional.class));
			
			if(hasLayout(layouts,DaoLayout.class)) {
				
				implPoint.add(new ImportCodePoint(PackageUtils.joinPackageName(packageName,relationModule.getPackageName(), BeanLayout.PACKAGE_NAME,relationModule.getName())));
				implPoint.add(new ImportCodePoint(PackageUtils.joinPackageName(packageName,relationModule.getPackageName(), ServiceLayout.PACKAGE_NAME,relationModule.getName()+"Service")));
				
				MemberCodePoint memberCodePoint = new MemberCodePoint(relationModule.getName()+"Service " + StringUtils.lowerFirstChar(relationModule.getName()) + "Service");
				memberCodePoint.setAnnotation(Autowired.class);
				implPoint.add(memberCodePoint);
			}
		}
		
		implPoint.add(new ImportCodePoint(PackageUtils.joinPackageName(packageName,moduleInfo.getPackageName(), BeanLayout.PACKAGE_NAME,moduleInfo.getName())));
		implPoint.add(new ImportCodePoint(PackageUtils.joinPackageName(packageName,moduleInfo.getPackageName(), BeanLayout.PACKAGE_NAME,moduleInfo.getName()+"Query")));
		implPoint.add(new ImportCodePoint(PackageUtils.joinPackageName(packageName,moduleInfo.getPackageName(), BeanLayout.PACKAGE_NAME,moduleInfo.getName()+"Service")));
		implPoint.add(new ImportCodePoint(Service.class));
		
		
		for(Layout l : layouts) {
			if(l instanceof DaoLayout) {
				implPoint.add(new ImportCodePoint(Autowired.class));
				implPoint.add(new ImportCodePoint(PackageUtils.joinPackageName(packageName,moduleInfo.getPackageName(), DaoLayout.PACKAGE_NAME,moduleInfo.getName()+"Dao")));
				MemberCodePoint memberCodePoint = new MemberCodePoint(moduleInfo.getName() + "Dao " + StringUtils.lowerFirstChar(moduleInfo.getName())+"Dao");
				memberCodePoint.setAnnotation(Autowired.class);
				implPoint.add(memberCodePoint);
				implPoint.add(new MethodBodyCodePoint("ADD",addCodes(moduleInfo)));
				implPoint.add(new MethodBodyCodePoint("UPDATE",updateCodes(moduleInfo)));
				implPoint.add(new MethodBodyCodePoint("DELETE",deleteCodes(moduleInfo)));
				implPoint.add(new MethodBodyCodePoint("GET",getCodes(moduleInfo)));
				implPoint.add(new MethodBodyCodePoint("LIST",listCodes(moduleInfo)));
			}
		}
		
		return pointMapping;
	}
	
	private String addCodes(ModuleInfo moduleInfo) {
		String varName = StringUtils.lowerFirstChar(moduleInfo.getName());
		RelationInfo relation = moduleInfo.getRelation();
		String relationStatement = "";
		if(relation != null) {
			ModuleInfo relationModule = relation.getRelationModule();
			String var = StringUtils.lowerFirstChar(relationModule.getName());
			String refVar = CodeUtils.varNewCustom(2, relationModule.getName(), var, StringUtils.lowerFirstChar(moduleInfo.getName()) + ".get" + relationModule.getName()+"()");
			relationStatement += refVar;
			String freServiceVar = CodeUtils.callMethod(0,StringUtils.lowerFirstChar(relationModule.getName())+"Service","add" + relationModule.getName(),var);
			
			relationStatement += CodeUtils.ifNullCondition(2, var, freServiceVar);
		}
		
		return CodeUtils.callMethod(0, varName + "Dao","add"+moduleInfo.getName(), varName) + relationStatement;
	}
	
	private String updateCodes(ModuleInfo moduleInfo) {
		String varName = StringUtils.lowerFirstChar(moduleInfo.getName());
		RelationInfo relation = moduleInfo.getRelation();
		String relationStatement = "";
		if(relation != null) {
			ModuleInfo relationModule = relation.getRelationModule();
			String var = StringUtils.lowerFirstChar(relationModule.getName());
			String refVar = CodeUtils.varNewCustom(2, relationModule.getName(), var, StringUtils.lowerFirstChar(moduleInfo.getName()) + ".get" + relationModule.getName()+"()");
			relationStatement += refVar;
			String freServiceVar = CodeUtils.callMethod(0,StringUtils.lowerFirstChar(relationModule.getName())+"Service","update" + relationModule.getName(),var);
			
			relationStatement += CodeUtils.ifNullCondition(2, var, freServiceVar);
		}
		return CodeUtils.callMethod(0,varName + "Dao","update" + moduleInfo.getName(), varName) + relationStatement;
	}
	
	private String deleteCodes(ModuleInfo moduleInfo) {
		return StringUtils.lowerFirstChar(moduleInfo.getName())+"Dao.delete"+moduleInfo.getName()+"(ids);";
	}
	
	private String getCodes(ModuleInfo moduleInfo) {
		return "return "+StringUtils.lowerFirstChar(moduleInfo.getName())+"Dao.get"+moduleInfo.getName()+"(id);";
	}
	
	private String listCodes(ModuleInfo moduleInfo) {
		return "return "+StringUtils.lowerFirstChar(moduleInfo.getName())+"Dao.list"+moduleInfo.getName()+"(query);";
	}
	
	private boolean hasLayout(Layout[] layouts,Class<?> layoutClass) {
		for (Layout layout : layouts) {
			if(layout.getClass() == layoutClass) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void init(ModuleInfo moduleInfo) {
		
	}
	

}
